import re
from collections import namedtuple
from operator import itemgetter


def parameter_debugger(arglist):
    '''
    Verify and correct `arglist` to meet the rules in Python

    Legal order of parameters:
        arg -> vararg -> kwarg -> varkwarg
    '''

    # define parameter structure
    ParamPool = namedtuple('ParamPool', ['arg', 'vararg', 'kwarg', 'varkwarg'])
    param_pool = ParamPool([], [], [], [])

    # check out the pattern of single parameter
    pat = re.compile(r'''^\s*(
        (?P<varkwarg>\*\*.*)|
        (?P<vararg>\*.*)|
        (?P<kwarg>.*?\s*=\s*.*)|
        (?P<arg>.*?))\s*$''', re.X)

    for index, arg in enumerate(arglist):
        _type, _value = next(
            filter(itemgetter(1), pat.match(arg).groupdict().items()))
        getattr(param_pool, _type).append((index, _value))

    # verify the parameters order
    order_list = [
        *map(itemgetter(0), param_pool.arg),
        *map(itemgetter(0), param_pool.vararg),
        *map(itemgetter(0), param_pool.kwarg),
        *map(itemgetter(0), param_pool.varkwarg),
    ]

    valid = all([
        sorted(order_list) == order_list,
        len(param_pool.vararg) <= 1,
        len(param_pool.varkwarg) <= 1
    ])

    # re-order parameter pool
    if not valid:
        if param_pool.vararg and len(param_pool.vararg) > 1:
            del param_pool.vararg[1:]

        if param_pool.varkwarg and len(param_pool.varkwarg) > 1:
            del param_pool.varkwarg[1:]

    params = tuple(map(itemgetter(1), [
        *param_pool.arg,
        *param_pool.vararg,
        *param_pool.kwarg,
        *param_pool.varkwarg,
    ]))

    return (params, valid)


if __name__ == "__main__":
    testcases = [
        ('slope', '*constants', 'intercept'),
        ('slope', 'intercept', '*constants'),
        ('slope', ),
        ('*constants', ),
        ('**kwargs', ),
        ('a=1', 'b = 2', '*c'),
        ('*args', '**kwargs'),
        ('*args1', '*args2'),
        ('**kwargs1', '**kwargs2'),
        ('**f', 'e=2', 'a', 'b=1', '*c'),
    ]

    for case in testcases:
        res = parameter_debugger(case)
        if res[1]:
            print(f'correct: {case}')
        else:
            print(f'origin: {case} | after: {res[0]}')

# origin: ('slope', '*constants', 'intercept') | after: ('slope', 'intercept', '*constants')
# correct: ('slope', 'intercept', '*constants')
# correct: ('slope',)
# correct: ('*constants',)
# correct: ('**kwargs',)
# origin: ('a=1', 'b = 2', '*c') | after: ('*c', 'a=1', 'b = 2')
# correct: ('*args', '**kwargs')
# origin: ('*args1', '*args2') | after: ('*args1',)
# origin: ('**kwargs1', '**kwargs2') | after: ('**kwargs1',)
# origin: ('**f', 'e=2', 'a', 'b=1', '*c') | after: ('a', '*c', 'e=2', 'b=1', '**f')
